/****************************************************************
 * Fulguro
 * Copyright (C) 2004 Christophe Clienti
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 ***************************************************************/

/* This file contains only HGW and Lemonnier algorithm */


#include <flgrCoreIO.h>
#include <flgrCoreMalloc.h>
#include <flgrCoreCopy.h>
#include <flgrCoreDispatch.h>
#include <flgrArith.h>

#include <flgrCoreTranspose.h>

#include "flgrMorphoBaseSegment.h"
#include "flgrMorphoBaseSegmentFast.h"


#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)<(y)?(x):(y))

/*!
 * \addtogroup group_fulguro_core_morpho_base
 * @{
 */



////////////////////////////////////////////////////////////////////////////
// Macro for Dilate one row using Lemonnier Algorithm
//////////////////////////////////////////////////////////////////
#define FLGR_MACRO_INTERNAL_DILATE_ROW_Lemonnier(dtype)			\
  int j;								\
  int nbprop;								\
  dtype T, T_pre;							\
  dtype G, G_pre;							\
  dtype rowval;								\
  dtype rowval_pre;							\
									\
  FLGR_DECLARE_FUNCTION;						\
									\
  sesize_x=sesize_x/2;							\
									\
  T=0;									\
  G=0;									\
  nbprop=0;								\
									\
  for( j=0 ; j<row_size ; j++) {					\
    T_pre=T;								\
    G_pre=G;								\
    rowval=flgr_get_array_##dtype(psrc,j);				\
									\
    if(j>(row_size-sesize_x-1)) {					\
      if(T_pre<rowval){							\
	T=rowval;							\
      }else {								\
	T=T_pre;							\
      }									\
    }else{								\
      T=0;								\
    }									\
									\
									\
    if( (G_pre>rowval) && (nbprop<sesize_x) ) {				\
      G=G_pre;								\
      nbprop++;								\
    }else {								\
      if( (j>(row_size-sesize_x-1)) && (nbprop>=sesize_x) ) {		\
	G=T;								\
      }else {								\
	G=rowval;							\
      }									\
      T=0;								\
      nbprop=0;								\
    }									\
									\
    if(j-sesize_x<0) {							\
      flgr_set_array_##dtype(tmp1,row_size-j-1,G);			\
    }else {								\
      flgr_set_array_##dtype(tmp1,					\
			     row_size-j-1,				\
			     max(G,flgr_get_array_##dtype(psrc,j-sesize_x))); \
    }									\
									\
  }									\
									\
  T=0;									\
  G=0;									\
  nbprop=0;								\
  rowval=0;								\
  rowval_pre=0;								\
									\
  for( j=0 ; j<row_size ; j++) {					\
    T_pre=T;								\
    G_pre=G;								\
									\
    rowval_pre=rowval;							\
    rowval=flgr_get_array_##dtype(tmp1,j);				\
									\
    if(j==0) {								\
      T=rowval;								\
    }else {								\
      if( (rowval>rowval_pre) && (T<rowval) ) {				\
	T=rowval;							\
      }else {								\
	T=T_pre;							\
      }									\
    }									\
									\
									\
    if( (G_pre>rowval) && (nbprop<sesize_x) ) {				\
      G=G_pre;								\
      nbprop++;								\
    }else {								\
      if (nbprop>=sesize_x) {						\
	G=T;								\
      }else{								\
	G=rowval;							\
      }									\
      T=0;								\
      nbprop=0;								\
    }									\
									\
    if(j<sesize_x) {							\
      flgr_set_array_##dtype(pdest,row_size-j-1,G);			\
    }else {								\
      flgr_set_array_##dtype(pdest,					\
			     row_size-j-1,				\
			     max(G,flgr_get_array_##dtype(tmp1,j-sesize_x))); \
    }									\
  }									\
									\
  return



////////////////////////////////////////////////////////////////////////////
// Macro for Dilate one row using Lemonnier Algorithm
//////////////////////////////////////////////////////////////////
#define FLGR_MACRO_INTERNAL_ERODE_ROW_Lemonnier(dtype)			\
  int j;								\
  int nbprop;								\
  dtype T, T_pre;							\
  dtype G, G_pre;							\
  dtype rowval;								\
  dtype rowval_pre;							\
									\
  FLGR_DECLARE_FUNCTION;						\
									\
  sesize_x=sesize_x/2;							\
									\
									\
									\
  T=0;									\
  G=0;									\
  nbprop=0;								\
									\
  for( j=0 ; j<row_size ; j++) {					\
    T_pre=T;								\
    G_pre=G;								\
    rowval=MAX_##dtype - flgr_get_array_##dtype(psrc,j);		\
									\
    if(j>(row_size-sesize_x-1)) {					\
      if(T_pre<rowval){							\
	T=rowval;							\
      }else {								\
	T=T_pre;							\
      }									\
    }else{								\
      T=0;								\
    }									\
									\
									\
    if( (G_pre>rowval) && (nbprop<sesize_x) ) {				\
      G=G_pre;								\
      nbprop++;								\
    }else {								\
      if( (j>(row_size-sesize_x-1)) && (nbprop>=sesize_x) ) {		\
	G=T;								\
      }else {								\
	G=rowval;							\
      }									\
      T=0;								\
      nbprop=0;								\
    }									\
									\
									\
    if(j-sesize_x<0) {							\
      flgr_set_array_##dtype(tmp1,row_size-j-1,G);			\
    }else {								\
      flgr_set_array_##dtype(tmp1,					\
			     row_size-j-1,				\
			     max(G,MAX_##dtype - flgr_get_array_##dtype(psrc,j-sesize_x))); \
    }									\
									\
  }									\
									\
  T=0;									\
  G=0;									\
  nbprop=0;								\
  rowval=0;								\
  rowval_pre=0;								\
									\
  for( j=0 ; j<row_size ; j++) {					\
    T_pre=T;								\
    G_pre=G;								\
									\
    rowval_pre=rowval;							\
    rowval=flgr_get_array_##dtype(tmp1,j);				\
									\
    if(j==0) {								\
      T=rowval;								\
    }else {								\
      if( (rowval>rowval_pre) && (T<rowval) ) {				\
	T=rowval;							\
      }else {								\
	T=T_pre;							\
      }									\
    }									\
									\
									\
    if( (G_pre>rowval) && (nbprop<sesize_x) ) {				\
      G=G_pre;								\
      nbprop++;								\
    }else {								\
      if (nbprop>=sesize_x) {						\
	G=T;								\
      }else{								\
	G=rowval;							\
      }									\
      T=0;								\
      nbprop=0;								\
    }									\
									\
    if(j<sesize_x) {							\
      flgr_set_array_##dtype(pdest,row_size-j-1,MAX_##dtype - G);	\
    }else {								\
      flgr_set_array_##dtype(pdest,					\
			     row_size-j-1,				\
			     MAX_##dtype - max(G,flgr_get_array_##dtype(tmp1,j-sesize_x))); \
    }									\
  }									\
									\
  return

////////////////////////////////////////////////////////////////////////////
// Macro for Dilate one row using HGW algorithm
//////////////////////////////////////////////////////////////////
#define FLGR_MACRO_INTERNAL_DILATE_ROW_HGW(dtype)			\
  int j,k,l,m=0,n=0,p=0,se2=sesize_x/2;					\
  int kpad;								\
  dtype *pbufg,*pbufh;							\
  dtype tmp;								\
  									\
  FLGR_DECLARE_FUNCTION;						\
									\
  pbufg=tmp1;								\
  pbufh=tmp2;								\
  									\
  tmp = flgr_get_array_##dtype(psrc,0);					\
  flgr_set_array_##dtype(pbufg,0,tmp);					\
									\
  tmp = flgr_get_array_##dtype(psrc,row_size-1);			\
  flgr_set_array_##dtype(pbufh,row_size-1,tmp);				\
									\
									\
  for( j=1,k=row_size-2,l=row_size-1 ; j<row_size ; j++,k--,l--) {	\
    if(j%sesize_x==0) {							\
      tmp = flgr_get_array_##dtype(psrc,j);				\
      flgr_set_array_##dtype(pbufg,j,tmp);				\
    }else {								\
      tmp = flgr_get_array_##dtype(pbufg,j-1);				\
      tmp = max(tmp, flgr_get_array_##dtype(psrc,j));			\
      flgr_set_array_##dtype(pbufg,j,tmp);				\
    }									\
    									\
    if(l%sesize_x==0) {							\
      tmp = flgr_get_array_##dtype(psrc,k);				\
      flgr_set_array_##dtype(pbufh,k,tmp);				\
    }else {								\
      tmp = flgr_get_array_##dtype(pbufh,l);				\
      tmp = max(tmp, flgr_get_array_##dtype(psrc,k));			\
      flgr_set_array_##dtype(pbufh,k,tmp);				\
    }									\
  }									\
									\
  n=se2;p=0;m=0;							\
  for( j=0; j<se2 ; j++) {						\
    tmp = flgr_get_array_##dtype(pbufg,n++);				\
    flgr_set_array_##dtype(pdest,m++,tmp);				\
  }									\
  for( j=se2; j<row_size-se2 ;j++) {					\
    tmp = flgr_get_array_##dtype(pbufg,n);				\
    tmp = max(tmp, flgr_get_array_##dtype(pbufh,p));			\
    flgr_set_array_##dtype(pdest,m,tmp);				\
    n++;p++;m++;							\
  }									\
  n--;									\
  kpad = row_size%sesize_x;						\
  kpad = (kpad==0) ? 0 : sesize_x-kpad;					\
  for( j=0 ; (j < kpad) && ( m < row_size); j++) {			\
    tmp = flgr_get_array_##dtype(pbufg,n);				\
    tmp = max(tmp, flgr_get_array_##dtype(pbufh,p));			\
    flgr_set_array_##dtype(pdest,m,tmp);				\
    m++;p++;								\
  }									\
  for( j=m ; j<row_size ; j++) {					\
    tmp = flgr_get_array_##dtype(pbufh,p++);				\
    flgr_set_array_##dtype(pdest,j,tmp);				\
  }									\
  									\
  return



////////////////////////////////////////////////////////////////////////////
// Macro for Dilate one row using HGW algorithm
//////////////////////////////////////////////////////////////////
#define FLGR_MACRO_INTERNAL_ERODE_ROW_HGW(dtype)			\
  int j,k,l,m=0,n=0,p=0,se2=sesize_x/2;					\
  int kpad;								\
  dtype *pbufg,*pbufh;							\
  dtype tmp;								\
  									\
  FLGR_DECLARE_FUNCTION;						\
									\
  pbufg=tmp1;								\
  pbufh=tmp2;								\
  									\
  tmp = flgr_get_array_##dtype(psrc,0);					\
  flgr_set_array_##dtype(pbufg,0,tmp);					\
									\
  tmp = flgr_get_array_##dtype(psrc,row_size-1);			\
  flgr_set_array_##dtype(pbufh,row_size-1,tmp);				\
									\
									\
  for( j=1,k=row_size-2,l=row_size-1 ; j<row_size ; j++,k--,l--) {	\
    if(j%sesize_x==0) {							\
      tmp = flgr_get_array_##dtype(psrc,j);				\
      flgr_set_array_##dtype(pbufg,j,tmp);				\
    }else {								\
      tmp = flgr_get_array_##dtype(pbufg,j-1);				\
      tmp = min(tmp, flgr_get_array_##dtype(psrc,j));			\
      flgr_set_array_##dtype(pbufg,j,tmp);				\
    }									\
    									\
    if(l%sesize_x==0) {							\
      tmp = flgr_get_array_##dtype(psrc,k);				\
      flgr_set_array_##dtype(pbufh,k,tmp);				\
    }else {								\
      tmp = flgr_get_array_##dtype(pbufh,l);				\
      tmp = min(tmp, flgr_get_array_##dtype(psrc,k));			\
      flgr_set_array_##dtype(pbufh,k,tmp);				\
    }									\
  }									\
									\
  n=se2;p=0;m=0;							\
  for( j=0; j<se2 ; j++) {						\
    tmp = flgr_get_array_##dtype(pbufg,n++);				\
    flgr_set_array_##dtype(pdest,m++,tmp);				\
  }									\
  for( j=se2; j<row_size-se2 ;j++) {					\
    tmp = flgr_get_array_##dtype(pbufg,n);				\
    tmp = min(tmp, flgr_get_array_##dtype(pbufh,p));			\
    flgr_set_array_##dtype(pdest,m,tmp);				\
    n++;p++;m++;							\
  }									\
  n--;									\
  kpad = row_size%sesize_x;						\
  kpad = (kpad==0) ? 0 : sesize_x-kpad;					\
  for( j=0 ; (j<kpad) && (m<row_size); j++) {				\
    tmp = flgr_get_array_##dtype(pbufg,n);				\
    tmp = min(tmp, flgr_get_array_##dtype(pbufh,p));			\
    flgr_set_array_##dtype(pdest,m,tmp);				\
    m++;p++;								\
  }									\
  for( j=m ; j<row_size ; j++) {					\
    tmp = flgr_get_array_##dtype(pbufh,p++);				\
    flgr_set_array_##dtype(pdest,j,tmp);				\
  }									\
									\
  return






void flgr1d_internal_dilate_line_fgBIT(fgBIT *pdest,fgBIT *psrc,
				       fgBIT *tmp1, fgBIT *tmp2,
				       int row_size, int sesize_x) {
  FLGR_MACRO_INTERNAL_DILATE_ROW_Lemonnier(fgBIT);
}
void flgr1d_internal_dilate_line_fgUINT8(fgUINT8 *pdest,fgUINT8 *psrc,
					 fgUINT8 *tmp1, fgUINT8 *tmp2,
					 int row_size, int sesize_x) {
  FLGR_MACRO_INTERNAL_DILATE_ROW_HGW(fgUINT8);
}
void flgr1d_internal_dilate_line_fgUINT16(fgUINT16 *pdest,fgUINT16 *psrc,
					  fgUINT16 *tmp1, fgUINT16 *tmp2,
					  int row_size, int sesize_x) {
  FLGR_MACRO_INTERNAL_DILATE_ROW_Lemonnier(fgUINT16);
}
void flgr1d_internal_dilate_line_fgUINT32(fgUINT32 *pdest,fgUINT32 *psrc,
					  fgUINT32 *tmp1, fgUINT32 *tmp2,
					  int row_size, int sesize_x) {
  FLGR_MACRO_INTERNAL_DILATE_ROW_Lemonnier(fgUINT32);
}
void flgr1d_internal_dilate_line_fgINT8(fgINT8 *pdest,fgINT8 *psrc,
					fgINT8 *tmp1, fgINT8 *tmp2,
					int row_size, int sesize_x) {
  FLGR_MACRO_INTERNAL_DILATE_ROW_Lemonnier(fgINT8);
}
void flgr1d_internal_dilate_line_fgINT16(fgINT16 *pdest,fgINT16 *psrc,
					 fgINT16 *tmp1, fgINT16 *tmp2,
					 int row_size, int sesize_x) {
  FLGR_MACRO_INTERNAL_DILATE_ROW_Lemonnier(fgINT16);
}
void flgr1d_internal_dilate_line_fgINT32(fgINT32 *pdest,fgINT32 *psrc,
					 fgINT32 *tmp1, fgINT32 *tmp2,
					 int row_size, int sesize_x) {
  FLGR_MACRO_INTERNAL_DILATE_ROW_Lemonnier(fgINT32);
}
void flgr1d_internal_dilate_line_fgFLOAT32(fgFLOAT32 *pdest,fgFLOAT32 *psrc,
					   fgFLOAT32 *tmp1, fgFLOAT32 *tmp2,
					   int row_size, int sesize_x) {
  FLGR_MACRO_INTERNAL_DILATE_ROW_Lemonnier(fgFLOAT32);
}
void flgr1d_internal_dilate_line_fgFLOAT64(fgFLOAT64 *pdest,fgFLOAT64 *psrc,
					   fgFLOAT64 *tmp1, fgFLOAT64 *tmp2,
					   int row_size, int sesize_x) {
  FLGR_MACRO_INTERNAL_DILATE_ROW_Lemonnier(fgFLOAT64);
}


void flgr1d_internal_erode_line_fgBIT(fgBIT *pdest,fgBIT *psrc,
				      fgBIT *tmp1, fgBIT *tmp2,
				      int row_size, int sesize_x) {
  FLGR_MACRO_INTERNAL_ERODE_ROW_Lemonnier(fgBIT);
}
void flgr1d_internal_erode_line_fgUINT8(fgUINT8 *pdest,fgUINT8 *psrc,
					fgUINT8 *tmp1, fgUINT8 *tmp2,
					int row_size, int sesize_x) {
  FLGR_MACRO_INTERNAL_ERODE_ROW_Lemonnier(fgUINT8);
}
void flgr1d_internal_erode_line_fgUINT16(fgUINT16 *pdest,fgUINT16 *psrc,
					 fgUINT16 *tmp1, fgUINT16 *tmp2,
					 int row_size, int sesize_x) {
  FLGR_MACRO_INTERNAL_ERODE_ROW_Lemonnier(fgUINT16);
}
void flgr1d_internal_erode_line_fgUINT32(fgUINT32 *pdest,fgUINT32 *psrc,
					 fgUINT32 *tmp1, fgUINT32 *tmp2,
					 int row_size, int sesize_x) {
  FLGR_MACRO_INTERNAL_ERODE_ROW_Lemonnier(fgUINT32);
}
void flgr1d_internal_erode_line_fgINT8(fgINT8 *pdest,fgINT8 *psrc,
				       fgINT8 *tmp1, fgINT8 *tmp2,
				       int row_size, int sesize_x) {
  FLGR_MACRO_INTERNAL_ERODE_ROW_Lemonnier(fgINT8);
}
void flgr1d_internal_erode_line_fgINT16(fgINT16 *pdest,fgINT16 *psrc,
					fgINT16 *tmp1, fgINT16 *tmp2,
					int row_size, int sesize_x) {
  FLGR_MACRO_INTERNAL_ERODE_ROW_Lemonnier(fgINT16);
}
void flgr1d_internal_erode_line_fgINT32(fgINT32 *pdest,fgINT32 *psrc,
					fgINT32 *tmp1, fgINT32 *tmp2,
					int row_size, int sesize_x) {
  FLGR_MACRO_INTERNAL_ERODE_ROW_Lemonnier(fgINT32);
}
void flgr1d_internal_erode_line_fgFLOAT32(fgFLOAT32 *pdest,fgFLOAT32 *psrc,
					  fgFLOAT32 *tmp1, fgFLOAT32 *tmp2,
					  int row_size, int sesize_x) {
  FLGR_MACRO_INTERNAL_ERODE_ROW_HGW(fgFLOAT32);
}
void flgr1d_internal_erode_line_fgFLOAT64(fgFLOAT64 *pdest,fgFLOAT64 *psrc,
					  fgFLOAT64 *tmp1, fgFLOAT64 *tmp2,
					  int row_size, int sesize_x) {
  FLGR_MACRO_INTERNAL_ERODE_ROW_HGW(fgFLOAT64);
}




////////////////////////////////////////////////////////
// Macro for flgr1d_dilate_line
////////////////////////////////////////////////////////
#define FLGR_MACRO_DILATE1D_LINE(dtype)					\
  dtype *psrc = (dtype*) datsrc->array;					\
  dtype *pdest = (dtype*) datdest->array;				\
  dtype *tmp1;								\
  dtype *tmp2;								\
  									\
  FLGR_DECLARE_FUNCTION;						\
									\
  tmp1 = (dtype*) flgr_malloc_align(datsrc->length*sizeof(dtype), 16);	\
  tmp2 = (dtype*) flgr_malloc_align(datsrc->length*sizeof(dtype), 16);	\
  									\
  flgr1d_internal_dilate_line_##dtype(pdest,psrc,tmp1,tmp2,		\
				      datsrc->length,sesize_x);		\
									\
  flgr_free_align(tmp1);						\
  flgr_free_align(tmp2)

void flgr1d_dilate_line_fgBIT(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int sesize_x) {
  FLGR_MACRO_DILATE1D_LINE(fgBIT);
}
void flgr1d_dilate_line_fgUINT8(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int sesize_x) {
  FLGR_MACRO_DILATE1D_LINE(fgUINT8);
}
void flgr1d_dilate_line_fgUINT16(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int sesize_x) {
  FLGR_MACRO_DILATE1D_LINE(fgUINT16);
}
void flgr1d_dilate_line_fgUINT32(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int sesize_x) {
  FLGR_MACRO_DILATE1D_LINE(fgUINT32);
}
void flgr1d_dilate_line_fgINT8(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int sesize_x) {
  FLGR_MACRO_DILATE1D_LINE(fgINT8);
}
void flgr1d_dilate_line_fgINT16(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int sesize_x) {
  FLGR_MACRO_DILATE1D_LINE(fgINT16);
}
void flgr1d_dilate_line_fgINT32(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int sesize_x) {
  FLGR_MACRO_DILATE1D_LINE(fgINT32);
}
void flgr1d_dilate_line_fgFLOAT32(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int sesize_x) {
  FLGR_MACRO_DILATE1D_LINE(fgFLOAT32);
}
void flgr1d_dilate_line_fgFLOAT64(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int sesize_x) {
  FLGR_MACRO_DILATE1D_LINE(fgFLOAT64);
}
////////////////////////////////////////////////////////////////////////////
/*! Dilate with line structuring element
 *  @param *datdest
 *  @param *datsrc
 *  @param *sesize_x
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr1d_dilate_line(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int sesize_x) {
  FLGR_Ret ret;

  FLGR_DECLARE_FUNCTION;

  if((datdest==NULL) || (datsrc==NULL)) {
    POST_ERROR("Null object\n");
    return FLGR_RET_NULL_OBJECT;
  }

  if((ret=flgr1d_is_data_same_attributes(datdest,datsrc,__FUNCTION__))!=FLGR_RET_OK) return ret;

  if(datsrc->spp!=1) {
    POST_ERROR("Could not process data with spp != 1!\n");
    return FLGR_RET_PARAM_ERROR;
  }

  if(sesize_x>datsrc->length) {
    POST_ERROR("fast dilation could not be done with se width > image width\n");
    return FLGR_RET_PARAM_ERROR;
  }

  FLGR_DISPATCH_PROCEDURE(datsrc->type,flgr1d_dilate_line,datdest,datsrc,sesize_x);
}



////////////////////////////////////////////////////////
// Macro for flgr1d_erode_line
////////////////////////////////////////////////////////
#define FLGR_MACRO_ERODE1D_LINE(dtype)					\
  dtype *psrc = (dtype*) datsrc->array;					\
  dtype *pdest = (dtype*) datdest->array;				\
  dtype *tmp1;								\
  dtype *tmp2;								\
  									\
  FLGR_DECLARE_FUNCTION;						\
									\
  tmp1 = (dtype*) flgr_malloc_align(datsrc->length*sizeof(dtype), 16);	\
  tmp2 = (dtype*) flgr_malloc_align(datsrc->length*sizeof(dtype), 16);	\
  									\
  flgr1d_internal_erode_line_##dtype(pdest,psrc,tmp1,tmp2,		\
				     datsrc->length,sesize_x);		\
									\
  flgr_free_align(tmp1);						\
  flgr_free_align(tmp2)

void flgr1d_erode_line_fgBIT(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int sesize_x) {
  FLGR_MACRO_ERODE1D_LINE(fgBIT);
}
void flgr1d_erode_line_fgUINT8(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int sesize_x) {
  FLGR_MACRO_ERODE1D_LINE(fgUINT8);
}
void flgr1d_erode_line_fgUINT16(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int sesize_x) {
  FLGR_MACRO_ERODE1D_LINE(fgUINT16);
}
void flgr1d_erode_line_fgUINT32(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int sesize_x) {
  FLGR_MACRO_ERODE1D_LINE(fgUINT32);
}
void flgr1d_erode_line_fgINT8(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int sesize_x) {
  FLGR_MACRO_ERODE1D_LINE(fgINT8);
}
void flgr1d_erode_line_fgINT16(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int sesize_x) {
  FLGR_MACRO_ERODE1D_LINE(fgINT16);
}
void flgr1d_erode_line_fgINT32(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int sesize_x) {
  FLGR_MACRO_ERODE1D_LINE(fgINT32);
}
void flgr1d_erode_line_fgFLOAT32(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int sesize_x) {
  FLGR_MACRO_ERODE1D_LINE(fgFLOAT32);
}
void flgr1d_erode_line_fgFLOAT64(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int sesize_x) {
  FLGR_MACRO_ERODE1D_LINE(fgFLOAT64);
}
////////////////////////////////////////////////////////////////////////////
/*! Erode with line structuring element
 *  @param *datdest
 *  @param *datsrc
 *  @param *sesize_x
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr1d_erode_line(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int sesize_x) {
  FLGR_Ret ret;

  FLGR_DECLARE_FUNCTION;

  if((datdest==NULL) || (datsrc==NULL)) {
    POST_ERROR("Null object\n");
    return FLGR_RET_NULL_OBJECT;
  }

  if((ret=flgr1d_is_data_same_attributes(datdest,datsrc,__FUNCTION__))!=FLGR_RET_OK) return ret;

  if(datsrc->spp!=1) {
    POST_ERROR("Could not process data with spp != 1!\n");
    return FLGR_RET_PARAM_ERROR;
  }

  if(sesize_x>datsrc->length) {
    POST_ERROR("fast erosion could not be done with se width > image width\n");
    return FLGR_RET_PARAM_ERROR;
  }

  FLGR_DISPATCH_PROCEDURE(datsrc->type,flgr1d_erode_line,datdest,datsrc,sesize_x);
}


////////////////////////////////////////////////////////////////////////////
/*! openning with line structuring element
 *  @param *datdest
 *  @param *datsrc
 *  @param *sesize_x
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr1d_open_line(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int sesize_x) {
  FLGR_Ret ret;
  FLGR_Data1D *dattmp;

  FLGR_DECLARE_FUNCTION;

  if((datdest==NULL) || (datsrc==NULL)){
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  dattmp =flgr1d_create_signal(datsrc->length, datsrc->spp, datsrc->type);
  if(dattmp==NULL) return FLGR_RET_ALLOCATION_ERROR;


  if((ret=flgr1d_erode_line(dattmp,datsrc,sesize_x))!=0)
    return ret;
  if((ret=flgr1d_dilate_line(datdest,dattmp,sesize_x))!=0)
    return ret;

  flgr1d_destroy(dattmp);

  return ret;
}

////////////////////////////////////////////////////////////////////////////
/*! closing with line structuring element
 *  @param *datdest
 *  @param *datsrc
 *  @param *sesize_x
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr1d_close_line(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int sesize_x) {
  FLGR_Ret ret;
  FLGR_Data1D *dattmp;

  FLGR_DECLARE_FUNCTION;

  if((datdest==NULL) || (datsrc==NULL)){
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  dattmp =flgr1d_create_signal(datsrc->length, datsrc->spp, datsrc->type);
  if(dattmp==NULL) return FLGR_RET_ALLOCATION_ERROR;


  if((ret=flgr1d_dilate_line(dattmp,datsrc,sesize_x))!=0)
    return ret;
  if((ret=flgr1d_erode_line(datdest,dattmp,sesize_x))!=0)
    return ret;

  flgr1d_destroy(dattmp);

  return ret;
}


////////////////////////////////////////////////////////////////////////////
/*! opentophat with line structuring element
 *  @param *datdest
 *  @param *datsrc
 *  @param *sesize_x
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr1d_open_tophat_line(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int sesize_x) {
  FLGR_Ret ret;
  FLGR_Data1D *dattmp;

  FLGR_DECLARE_FUNCTION;

  if((datdest==NULL) || (datsrc==NULL)){
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  dattmp =flgr1d_create_signal(datsrc->length, datsrc->spp, datsrc->type);
  if(dattmp==NULL) return FLGR_RET_ALLOCATION_ERROR;


  if((ret=flgr1d_erode_line(dattmp,datsrc,sesize_x))!=0)
    return ret;
  if((ret=flgr1d_dilate_line(datdest,dattmp,sesize_x))!=0)
    return ret;
  if((ret=flgr1d_arith_sub(datdest,datsrc,datdest))!=0)
    return ret;


  flgr1d_destroy(dattmp);

  return ret;
}

////////////////////////////////////////////////////////////////////////////
/*! closetophat with line structuring element
 *  @param *datdest
 *  @param *datsrc
 *  @param *sesize_x
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr1d_close_tophat_line(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int sesize_x) {
  FLGR_Ret ret;
  FLGR_Data1D *dattmp;

  FLGR_DECLARE_FUNCTION;

  if((datdest==NULL) || (datsrc==NULL)){
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  dattmp =flgr1d_create_signal(datsrc->length, datsrc->spp, datsrc->type);
  if(dattmp==NULL) return FLGR_RET_ALLOCATION_ERROR;


  if((ret=flgr1d_dilate_line(dattmp,datsrc,sesize_x))!=0)
    return ret;
  if((ret=flgr1d_erode_line(datdest,dattmp,sesize_x))!=0)
    return ret;
  if((ret=flgr1d_arith_sub(datdest,datdest,datsrc))!=0)
    return ret;


  flgr1d_destroy(dattmp);

  return ret;
}





////////////////////////////////////////////////////////
// Macro for flgr1d_erode_line
////////////////////////////////////////////////////////
#define FLGR_MACRO_DILATE2D_LINE(dtype)					\
  dtype *psrc;								\
  dtype *pdest;								\
  dtype *tmp1;								\
  dtype *tmp2;								\
  int i;								\
  									\
  FLGR_DECLARE_FUNCTION;						\
									\
  tmp1 = (dtype*) flgr_malloc_align(datsrc->size_x*sizeof(dtype), 16);	\
  tmp2 = (dtype*) flgr_malloc_align(datsrc->size_x*sizeof(dtype), 16);	\
  									\
  for(i=0 ; i<datsrc->size_y ; i++) {					\
    psrc = (dtype*) datsrc->array[i];					\
    pdest = (dtype*) datdest->array[i];					\
    flgr1d_internal_dilate_line_##dtype(pdest,psrc,tmp1,tmp2,		\
					datsrc->size_x,sesize_x);	\
  }									\
									\
									\
  flgr_free_align(tmp1);						\
  flgr_free_align(tmp2)

void flgr2d_dilate_line_horizontal_fgBIT(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int sesize_x) {
  FLGR_MACRO_DILATE2D_LINE(fgBIT);
}
void flgr2d_dilate_line_horizontal_fgUINT8(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int sesize_x) {
#if  defined(__SSE2__) || (defined(__SSE__) && defined(__MMX__))
  FLGR_DECLARE_FUNCTION;
  flgr2d_dilate_segment_horizontal_fast_fgUINT8(datdest,datsrc,sesize_x);
#else
  FLGR_MACRO_DILATE2D_LINE(fgUINT8);
#endif
}
void flgr2d_dilate_line_horizontal_fgUINT16(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int sesize_x) {
  FLGR_MACRO_DILATE2D_LINE(fgUINT16);
}
void flgr2d_dilate_line_horizontal_fgUINT32(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int sesize_x) {
  FLGR_MACRO_DILATE2D_LINE(fgUINT32);
}
void flgr2d_dilate_line_horizontal_fgINT8(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int sesize_x) {
  FLGR_MACRO_DILATE2D_LINE(fgINT8);
}
void flgr2d_dilate_line_horizontal_fgINT16(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int sesize_x) {
  FLGR_MACRO_DILATE2D_LINE(fgINT16);
}
void flgr2d_dilate_line_horizontal_fgINT32(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int sesize_x) {
  FLGR_MACRO_DILATE2D_LINE(fgINT32);
}
void flgr2d_dilate_line_horizontal_fgFLOAT32(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int sesize_x) {
  FLGR_MACRO_DILATE2D_LINE(fgFLOAT32);
}
void flgr2d_dilate_line_horizontal_fgFLOAT64(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int sesize_x) {
  FLGR_MACRO_DILATE2D_LINE(fgFLOAT64);
}
////////////////////////////////////////////////////////////////////////////
/*! Dilate with line structuring element
 *  @param *datdest
 *  @param *datsrc
 *  @param *sesize_x
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_dilate_line_horizontal(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int sesize_x) {
  FLGR_Ret ret;

  FLGR_DECLARE_FUNCTION;

  if((datdest==NULL) || (datsrc==NULL)) {
    POST_ERROR("Null object\n");
    return FLGR_RET_NULL_OBJECT;
  }

  if((ret=flgr2d_is_data_same_attributes(datdest,datsrc,__FUNCTION__))!=FLGR_RET_OK) return ret;

  if(datsrc->spp!=1) {
    POST_ERROR("Could not process data with spp != 1!\n");
    return FLGR_RET_PARAM_ERROR;
  }

  if(sesize_x>datsrc->size_x) {
    POST_ERROR("fast dilation could not be done with se width > image width\n");
    return FLGR_RET_PARAM_ERROR;
  }

  FLGR_DISPATCH_PROCEDURE(datsrc->type,flgr2d_dilate_line_horizontal,datdest,datsrc,sesize_x);
}




////////////////////////////////////////////////////////
// Macro for flgr1d_erode_line
////////////////////////////////////////////////////////
#define FLGR_MACRO_ERODE2D_LINE(dtype)					\
  dtype *psrc;								\
  dtype *pdest;								\
  dtype *tmp1;								\
  dtype *tmp2;								\
  int i;								\
  									\
  FLGR_DECLARE_FUNCTION;						\
									\
  tmp1 = (dtype*) flgr_malloc_align(datsrc->size_x*sizeof(dtype), 16);	\
  tmp2 = (dtype*) flgr_malloc_align(datsrc->size_x*sizeof(dtype), 16);	\
  									\
  for(i=0 ; i<datsrc->size_y ; i++) {					\
    psrc = (dtype*) datsrc->array[i];					\
    pdest = (dtype*) datdest->array[i];					\
    flgr1d_internal_erode_line_##dtype(pdest,psrc,tmp1,tmp2,		\
				       datsrc->size_x,sesize_x);	\
  }									\
									\
									\
  flgr_free_align(tmp1);						\
  flgr_free_align(tmp2)

void flgr2d_erode_line_horizontal_fgBIT(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int sesize_x) {
  FLGR_MACRO_ERODE2D_LINE(fgBIT);
}
void flgr2d_erode_line_horizontal_fgUINT8(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int sesize_x) {
#if  defined(__SSE2__) || (defined(__SSE__) && defined(__MMX__))
  FLGR_DECLARE_FUNCTION;
  flgr2d_erode_segment_horizontal_fast_fgUINT8(datdest,datsrc,sesize_x);
#else
  FLGR_MACRO_ERODE2D_LINE(fgUINT8);
#endif
}
void flgr2d_erode_line_horizontal_fgUINT16(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int sesize_x) {
  FLGR_MACRO_ERODE2D_LINE(fgUINT16);
}
void flgr2d_erode_line_horizontal_fgUINT32(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int sesize_x) {
  FLGR_MACRO_ERODE2D_LINE(fgUINT32);
}
void flgr2d_erode_line_horizontal_fgINT8(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int sesize_x) {
  FLGR_MACRO_ERODE2D_LINE(fgINT8);
}
void flgr2d_erode_line_horizontal_fgINT16(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int sesize_x) {
  FLGR_MACRO_ERODE2D_LINE(fgINT16);
}
void flgr2d_erode_line_horizontal_fgINT32(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int sesize_x) {
  FLGR_MACRO_ERODE2D_LINE(fgINT32);
}
void flgr2d_erode_line_horizontal_fgFLOAT32(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int sesize_x) {
  FLGR_MACRO_ERODE2D_LINE(fgFLOAT32);
}
void flgr2d_erode_line_horizontal_fgFLOAT64(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int sesize_x) {
  FLGR_MACRO_ERODE2D_LINE(fgFLOAT64);
}
////////////////////////////////////////////////////////////////////////////
/*! Erode with line structuring element
 *  @param *datdest
 *  @param *datsrc
 *  @param *sesize_x
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_erode_line_horizontal(FLGR_Data2D *datdest, FLGR_Data2D *datsrc, int sesize_x) {
  FLGR_Ret ret;

  FLGR_DECLARE_FUNCTION;

  if((datdest==NULL) || (datsrc==NULL)) {
    POST_ERROR("Null object\n");
    return FLGR_RET_NULL_OBJECT;
  }

  if((ret=flgr2d_is_data_same_attributes(datdest,datsrc,__FUNCTION__))!=FLGR_RET_OK) return ret;

  if(datsrc->spp!=1) {
    POST_ERROR("Could not process data with spp != 1!\n");
    return FLGR_RET_PARAM_ERROR;
  }

  if(sesize_x>datsrc->size_x) {
    POST_ERROR("fast erosion could not be done with se width > image width\n");
    return FLGR_RET_PARAM_ERROR;
  }


  FLGR_DISPATCH_PROCEDURE(datsrc->type,flgr2d_erode_line_horizontal,datdest,datsrc,sesize_x);
}




////////////////////////////////////////////////////////////////////////////
// Macro for different type of flgr2d_dilate_rectangle
//////////////////////////////////////////////////////////////////
#define FLGR_MACRO_ERODE_DILATE_2D_RECTANGLE(op,dtype)		\
  FLGR_Data2D *img1,*img2,*img3;				\
								\
  FLGR_DECLARE_FUNCTION;					\
								\
  img1 = flgr2d_create_##dtype(imgsrc->size_y,imgsrc->size_x,	\
			       imgsrc->spp,			\
			       FLGR_NO_SHAPE,FLGR_NO_CONNEX);	\
								\
  img2 = flgr2d_create_##dtype(imgsrc->size_x,imgsrc->size_y,	\
			       imgsrc->spp,			\
			       FLGR_NO_SHAPE,FLGR_NO_CONNEX);	\
								\
  img3 = flgr2d_create_##dtype(imgsrc->size_x,imgsrc->size_y,	\
			       imgsrc->spp,			\
			       FLGR_NO_SHAPE,FLGR_NO_CONNEX);	\
								\
  flgr2d_##op##_line_horizontal_##dtype(img1,imgsrc,sesize_x);	\
								\
  flgr2d_transpose_##dtype(img2,img1);				\
								\
  flgr2d_##op##_line_horizontal_##dtype(img3,img2,sesize_y);	\
								\
  flgr2d_transpose_##dtype(imgdest,img3);			\
								\
  flgr2d_destroy(img1);						\
  flgr2d_destroy(img2);						\
  flgr2d_destroy(img3)


void flgr2d_dilate_rectangle_fgBIT(FLGR_Data2D *imgdest, FLGR_Data2D *imgsrc, int sesize_x, int sesize_y) {
  FLGR_MACRO_ERODE_DILATE_2D_RECTANGLE(dilate,fgBIT);
}
void flgr2d_dilate_rectangle_fgUINT8(FLGR_Data2D *imgdest, FLGR_Data2D *imgsrc, int sesize_x, int sesize_y) {
#if  defined(__SSE2__) || ((defined(__SSE__) && defined(__MMX__)))
  FLGR_Data2D *imgtmp;

  FLGR_DECLARE_FUNCTION;

  if((sesize_x==1) && (sesize_y==1)) {
    flgr2d_copy(imgdest,imgsrc);
  }else if((sesize_x==1) && (sesize_y!=1)) {
    flgr2d_dilate_segment_vertical_fast_fgUINT8(imgdest,imgsrc,sesize_y);
  }else if((sesize_x!=1) && (sesize_y==1)) {
    flgr2d_dilate_segment_horizontal_fast_fgUINT8(imgdest,imgsrc,sesize_x);
  }else{
    imgtmp = flgr2d_create_from(imgsrc);
    flgr2d_dilate_segment_horizontal_fast_fgUINT8(imgtmp,imgsrc,sesize_x);
    flgr2d_dilate_segment_vertical_fast_fgUINT8(imgdest,imgtmp,sesize_y);
    flgr2d_destroy(imgtmp);
  }

#else
  FLGR_MACRO_ERODE_DILATE_2D_RECTANGLE(dilate,fgUINT8);
#endif
}
void flgr2d_dilate_rectangle_fgUINT16(FLGR_Data2D *imgdest, FLGR_Data2D *imgsrc, int sesize_x, int sesize_y) {
  FLGR_MACRO_ERODE_DILATE_2D_RECTANGLE(dilate,fgUINT16);
}
void flgr2d_dilate_rectangle_fgUINT32(FLGR_Data2D *imgdest, FLGR_Data2D *imgsrc, int sesize_x, int sesize_y) {
  FLGR_MACRO_ERODE_DILATE_2D_RECTANGLE(dilate,fgUINT32);
}
void flgr2d_dilate_rectangle_fgINT8(FLGR_Data2D *imgdest, FLGR_Data2D *imgsrc, int sesize_x, int sesize_y) {
  FLGR_MACRO_ERODE_DILATE_2D_RECTANGLE(dilate,fgINT8);
}
void flgr2d_dilate_rectangle_fgINT16(FLGR_Data2D *imgdest, FLGR_Data2D *imgsrc, int sesize_x, int sesize_y) {
  FLGR_MACRO_ERODE_DILATE_2D_RECTANGLE(dilate,fgINT16);
}
void flgr2d_dilate_rectangle_fgINT32(FLGR_Data2D *imgdest, FLGR_Data2D *imgsrc, int sesize_x, int sesize_y) {
  FLGR_MACRO_ERODE_DILATE_2D_RECTANGLE(dilate,fgINT32);
}
void flgr2d_dilate_rectangle_fgFLOAT32(FLGR_Data2D *imgdest, FLGR_Data2D *imgsrc, int sesize_x, int sesize_y) {
  FLGR_MACRO_ERODE_DILATE_2D_RECTANGLE(dilate,fgFLOAT32);
}
void flgr2d_dilate_rectangle_fgFLOAT64(FLGR_Data2D *imgdest, FLGR_Data2D *imgsrc, int sesize_x, int sesize_y) {
  FLGR_MACRO_ERODE_DILATE_2D_RECTANGLE(dilate,fgFLOAT64);
}

void flgr2d_erode_rectangle_fgBIT(FLGR_Data2D *imgdest, FLGR_Data2D *imgsrc, int sesize_x, int sesize_y) {
  FLGR_MACRO_ERODE_DILATE_2D_RECTANGLE(erode,fgBIT);
}
void flgr2d_erode_rectangle_fgUINT8(FLGR_Data2D *imgdest, FLGR_Data2D *imgsrc, int sesize_x, int sesize_y) {
#if  defined(__SSE2__) || (defined(__SSE__) && defined(__MMX__))
  FLGR_Data2D *imgtmp;

  FLGR_DECLARE_FUNCTION;

  if((sesize_x==1) && (sesize_y==1)) {
    flgr2d_copy(imgdest,imgsrc);
  }else if((sesize_x==1) && (sesize_y!=1)) {
    flgr2d_erode_segment_vertical_fast_fgUINT8(imgdest,imgsrc,sesize_y);
  }else if((sesize_x!=1) && (sesize_y==1)) {
    flgr2d_erode_segment_horizontal_fast_fgUINT8(imgdest,imgsrc,sesize_x);
  }else{
    imgtmp = flgr2d_create_from(imgsrc);
    flgr2d_erode_segment_horizontal_fast_fgUINT8(imgtmp,imgsrc,sesize_x);
    flgr2d_erode_segment_vertical_fast_fgUINT8(imgdest,imgtmp,sesize_y);
    flgr2d_destroy(imgtmp);
  }

#else
  FLGR_MACRO_ERODE_DILATE_2D_RECTANGLE(erode,fgUINT8);
#endif
}
void flgr2d_erode_rectangle_fgUINT16(FLGR_Data2D *imgdest, FLGR_Data2D *imgsrc, int sesize_x, int sesize_y) {
  FLGR_MACRO_ERODE_DILATE_2D_RECTANGLE(erode,fgUINT16);
}
void flgr2d_erode_rectangle_fgUINT32(FLGR_Data2D *imgdest, FLGR_Data2D *imgsrc, int sesize_x, int sesize_y) {
  FLGR_MACRO_ERODE_DILATE_2D_RECTANGLE(erode,fgUINT32);
}
void flgr2d_erode_rectangle_fgINT8(FLGR_Data2D *imgdest, FLGR_Data2D *imgsrc, int sesize_x, int sesize_y) {
  FLGR_MACRO_ERODE_DILATE_2D_RECTANGLE(erode,fgINT8);
}
void flgr2d_erode_rectangle_fgINT16(FLGR_Data2D *imgdest, FLGR_Data2D *imgsrc, int sesize_x, int sesize_y) {
  FLGR_MACRO_ERODE_DILATE_2D_RECTANGLE(erode,fgINT16);
}
void flgr2d_erode_rectangle_fgINT32(FLGR_Data2D *imgdest, FLGR_Data2D *imgsrc, int sesize_x, int sesize_y) {
  FLGR_MACRO_ERODE_DILATE_2D_RECTANGLE(erode,fgINT32);
}
void flgr2d_erode_rectangle_fgFLOAT32(FLGR_Data2D *imgdest, FLGR_Data2D *imgsrc, int sesize_x, int sesize_y) {
  FLGR_MACRO_ERODE_DILATE_2D_RECTANGLE(erode,fgFLOAT32);
}
void flgr2d_erode_rectangle_fgFLOAT64(FLGR_Data2D *imgdest, FLGR_Data2D *imgsrc, int sesize_x, int sesize_y) {
  FLGR_MACRO_ERODE_DILATE_2D_RECTANGLE(erode,fgFLOAT64);
}



////////////////////////////////////////////////////////////////////////////
/*! \brief Dilate2d a Image with a rectangular centered structuring element
 *  @param *imgdest : destination image
 *  @param *imgsrc : source image
 *  @param sesize_x : size_x of the linear centered structuring elements
 *  @param sesize_y : size_y of the linear centered structuring elements
 *  @returns -1 if image does not have the right type or if image dest and src have differents properties
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_dilate_rectangle(FLGR_Data2D *imgdest, FLGR_Data2D *imgsrc, int sesize_x, int sesize_y) {
  FLGR_Ret ret;

  FLGR_DECLARE_FUNCTION;

  if((imgdest==NULL) || (imgsrc==NULL)){
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }


  if((ret=flgr2d_is_data_same_attributes(imgdest,imgsrc,__FUNCTION__))!=FLGR_RET_OK) return ret;

  if(imgsrc->spp!=1) {
    POST_ERROR("Could not process data with spp != 1!\n");
    return FLGR_RET_PARAM_ERROR;
  }

  if(sesize_y>imgsrc->size_y) {
    POST_ERROR("fast dilation could not be done with se height > image height\n");
    return FLGR_RET_PARAM_ERROR;
  }

  if(sesize_x>imgsrc->size_x) {
    POST_ERROR("fast dilation could not be done with se width > image width\n");
    return FLGR_RET_PARAM_ERROR;
  }

  FLGR_DISPATCH_PROCEDURE(imgdest->type,flgr2d_dilate_rectangle,imgdest,imgsrc,sesize_x,sesize_y);

}


////////////////////////////////////////////////////////////////////////////
/*! \brief Erode2d a Image with a rectangular centered structuring element
 *  @param *imgdest : destination image
 *  @param *imgsrc : source image
 *  @param sesize_x : size_x of the linear centered structuring elements
 *  @param sesize_y : size_y of the linear centered structuring elements
 *  @returns -1 if image does not have the right type or if image dest and src have differents properties
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_erode_rectangle(FLGR_Data2D *imgdest, FLGR_Data2D *imgsrc, int sesize_x, int sesize_y) {
  FLGR_Ret ret;

  FLGR_DECLARE_FUNCTION;

  if((imgdest==NULL) || (imgsrc==NULL)){
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  if((ret=flgr2d_is_data_same_attributes(imgdest,imgsrc,__FUNCTION__))!=FLGR_RET_OK) return ret;

  if(imgsrc->spp!=1) {
    POST_ERROR("Could not process data with spp != 1!\n");
    return FLGR_RET_PARAM_ERROR;
  }

  if(sesize_y>imgsrc->size_y) {
    POST_ERROR("fast erosion could not be done with se height > image height\n");
    return FLGR_RET_NOT_IMPLEMENTED;
  }

  if(sesize_x>imgsrc->size_x) {
    POST_ERROR("fast erosion could not be done with se width > image width\n");
    return FLGR_RET_NOT_IMPLEMENTED;
  }

  FLGR_DISPATCH_PROCEDURE(imgdest->type,flgr2d_erode_rectangle,imgdest,imgsrc,sesize_x,sesize_y);

}





////////////////////////////////////////////////////////////////////////////
/*! \brief Open2d a Image with a linear centered structuring element
 *  @param *imgdest : destination image
 *  @param *imgsrc : source im  Im(imgtmp,img,&nhb);
 age
 *  @param sesize_x : size_x of the linear centered structuring elements
 *  @returns -1 if image does not have the right type or if image dest and src have differents properties
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_open_line_horizontal(FLGR_Data2D *imgdest, FLGR_Data2D *imgsrc, int sesize_x) {
  FLGR_Ret ret;
  FLGR_Data2D *imgtmp;

  FLGR_DECLARE_FUNCTION;

  if((imgdest==NULL) || (imgsrc==NULL)){
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  imgtmp =flgr2d_create_pixmap(imgsrc->size_y, imgsrc->size_x,imgsrc->spp, imgsrc->type);
  if(imgtmp==NULL) return FLGR_RET_ALLOCATION_ERROR;


  if((ret=flgr2d_erode_line_horizontal(imgtmp,imgsrc,sesize_x))!=0)
    return ret;
  if((ret=flgr2d_dilate_line_horizontal(imgdest,imgtmp,sesize_x))!=0)
    return ret;

  flgr2d_destroy(imgtmp);

  return ret;

}

////////////////////////////////////////////////////////////////////////////
/*! \brief Close2d a Image with a linear centered structuring element
 *  @param *imgdest : destination image
 *  @param *imgsrc : source image
 *  @param sesize_x : size_x of the linear centered structuring elements
 *  @returns -1 if image does not have the right type or if image dest and src have differents properties
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_close_line_horizontal(FLGR_Data2D *imgdest, FLGR_Data2D *imgsrc, int sesize_x) {
  FLGR_Ret ret;
  FLGR_Data2D *imgtmp;

  FLGR_DECLARE_FUNCTION;

  if((imgdest==NULL) || (imgsrc==NULL)){
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  imgtmp =flgr2d_create_pixmap(imgsrc->size_y, imgsrc->size_x,imgsrc->spp, imgsrc->type);
  if(imgtmp==NULL) return FLGR_RET_ALLOCATION_ERROR;

  if((ret=flgr2d_dilate_line_horizontal(imgtmp,imgsrc,sesize_x))!=0)
    return ret;
  if((ret=flgr2d_erode_line_horizontal(imgdest,imgtmp,sesize_x))!=0)
    return ret;

  flgr2d_destroy(imgtmp);

  return ret;

}


////////////////////////////////////////////////////////////////////////////
/*! \brief Open2d a Image with a rectangular centered structuring element
 *  @param *imgdest : destination image
 *  @param *imgsrc : source image
 *  @param sesize_x : size_x of the linear centered structuring elements
 *  @param sesize_y : size_y of the linear centered structuring elements
 *  @returns -1 if image does not have the right type or if image dest and src have differents properties
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_open_rectangle(FLGR_Data2D *imgdest, FLGR_Data2D *imgsrc, int sesize_x, int sesize_y) {
  FLGR_Ret ret;
  FLGR_Data2D *imgtmp;

  FLGR_DECLARE_FUNCTION;

  if((imgdest==NULL) || (imgsrc==NULL)){
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  imgtmp =flgr2d_create_pixmap(imgsrc->size_y, imgsrc->size_x,imgsrc->spp, imgsrc->type);
  if(imgtmp==NULL) return FLGR_RET_ALLOCATION_ERROR;

  if((ret=flgr2d_erode_rectangle(imgtmp,imgsrc,sesize_x,sesize_y))!=0)
    return ret;
  if((ret=flgr2d_dilate_rectangle(imgdest,imgtmp,sesize_x,sesize_y))!=0)
    return ret;

  flgr2d_destroy(imgtmp);

  return ret;

}


////////////////////////////////////////////////////////////////////////////
/*! \brief Close2d a Image with a rectangular centered structuring element
 *  @param *imgdest : destination image
 *  @param *imgsrc : source image
 *  @param sesize_x : size_x of the linear centered structuring elements
 *  @param sesize_y : size_y of the linear centered structuring elements
 *  @returns -1 if image does not have the right type or if image dest and src have differents properties
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_close_rectangle(FLGR_Data2D *imgdest, FLGR_Data2D *imgsrc, int sesize_x, int sesize_y) {
  FLGR_Ret ret;
  FLGR_Data2D *imgtmp;

  FLGR_DECLARE_FUNCTION;

  if((imgdest==NULL) || (imgsrc==NULL)){
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  imgtmp =flgr2d_create_pixmap(imgsrc->size_y, imgsrc->size_x,imgsrc->spp, imgsrc->type);
  if(imgtmp==NULL) return FLGR_RET_ALLOCATION_ERROR;

  if((ret=flgr2d_dilate_rectangle(imgtmp,imgsrc,sesize_x,sesize_y))!=0)
    return ret;
  if((ret=flgr2d_erode_rectangle(imgdest,imgtmp,sesize_x,sesize_y))!=0)
    return ret;

  flgr2d_destroy(imgtmp);

  return ret;

}



////////////////////////////////////////////////////////////////////////////
/*! \brief Open2d a Image with a linear centered structuring element
 *  @param *imgdest : destination image
 *  @param *imgsrc : source image
 *  @param sesize_x : size_x of the linear centered structuring elements
 *  @returns -1 if image does not have the right type or if image dest and src have differents properties
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_open_tophat_line_horizontal(FLGR_Data2D *imgdest, FLGR_Data2D *imgsrc, int sesize_x) {
  FLGR_Ret ret;
  FLGR_Data2D *imgtmp;

  FLGR_DECLARE_FUNCTION;

  if((imgdest==NULL) || (imgsrc==NULL)){
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  imgtmp =flgr2d_create_pixmap(imgsrc->size_y, imgsrc->size_x,imgsrc->spp, imgsrc->type);
  if(imgtmp==NULL) return FLGR_RET_ALLOCATION_ERROR;

  if((ret=flgr2d_erode_line_horizontal(imgtmp,imgsrc,sesize_x))!=0)
    return ret;
  if((ret=flgr2d_dilate_line_horizontal(imgdest,imgtmp,sesize_x))!=0)
    return ret;

  flgr2d_arith_sub(imgdest,imgsrc,imgdest);

  flgr2d_destroy(imgtmp);

  return ret;

}

////////////////////////////////////////////////////////////////////////////
/*! \brief Close2d a Image with a linear centered structuring element
 *  @param *imgdest : destination image
 *  @param *imgsrc : source image
 *  @param sesize_x : size_x of the linear centered structuring elements
 *  @returns -1 if image does not have the right type or if image dest and src have differents properties
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_close_tophat_line_horizontal(FLGR_Data2D *imgdest, FLGR_Data2D *imgsrc, int sesize_x) {
  FLGR_Ret ret;
  FLGR_Data2D *imgtmp;

  FLGR_DECLARE_FUNCTION;

  if((imgdest==NULL) || (imgsrc==NULL)){
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  imgtmp =flgr2d_create_pixmap(imgsrc->size_y, imgsrc->size_x,imgsrc->spp, imgsrc->type);
  if(imgtmp==NULL) return FLGR_RET_ALLOCATION_ERROR;

  if((ret=flgr2d_dilate_line_horizontal(imgtmp,imgsrc,sesize_x))!=0)
    return ret;
  if((ret=flgr2d_erode_line_horizontal(imgdest,imgtmp,sesize_x))!=0)
    return ret;

  flgr2d_arith_sub(imgdest,imgdest,imgsrc);

  flgr2d_destroy(imgtmp);

  return ret;

}




////////////////////////////////////////////////////////////////////////////
/*! \brief Open2d TopHat a Image with a rectangular centered structuring element
 *  @param *imgdest : destination image
 *  @param *imgsrc : source image
 *  @param sesize_x : size_x of the linear centered structuring elements
 *  @param sesize_y : size_y of the linear centered structuring elements
 *  @returns -1 if image does not have the right type or if image dest and src have differents properties
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_open_tophat_rectangle(FLGR_Data2D *imgdest, FLGR_Data2D *imgsrc, int sesize_x, int sesize_y) {
  FLGR_Ret ret;
  FLGR_Data2D *imgtmp;

  FLGR_DECLARE_FUNCTION;

  if((imgdest==NULL) || (imgsrc==NULL)){
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  imgtmp =flgr2d_create_pixmap(imgsrc->size_y, imgsrc->size_x,imgsrc->spp, imgsrc->type);
  if(imgtmp==NULL) return FLGR_RET_ALLOCATION_ERROR;

  if((ret=flgr2d_erode_rectangle(imgtmp,imgsrc,sesize_x,sesize_y))!=0)
    return ret;
  if((ret=flgr2d_dilate_rectangle(imgdest,imgtmp,sesize_x,sesize_y))!=0)
    return ret;

  if((ret=flgr2d_arith_sub(imgdest,imgsrc,imgdest))!=0)
    return ret;

  flgr2d_destroy(imgtmp);

  return ret;

}

////////////////////////////////////////////////////////////////////////////
/*! \brief Close2d TopHat a Image with a rectangular centered structuring element
 *  @param *imgdest : destination image
 *  @param *imgsrc : source image
 *  @param sesize_x : size_x of the linear centered structuring elements
 *  @param sesize_y : size_y of the linear centered structuring elements
 *  @returns -1 if image does not have the right type or if image dest and src have differents properties
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_close_tophat_rectangle(FLGR_Data2D *imgdest, FLGR_Data2D *imgsrc, int sesize_x, int sesize_y) {
  FLGR_Ret ret;
  FLGR_Data2D *imgtmp;

  FLGR_DECLARE_FUNCTION;

  if((imgdest==NULL) || (imgsrc==NULL)){
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  imgtmp =flgr2d_create_pixmap(imgsrc->size_y, imgsrc->size_x,imgsrc->spp, imgsrc->type);
  if(imgtmp==NULL) return FLGR_RET_ALLOCATION_ERROR;

  if((ret=flgr2d_dilate_rectangle(imgtmp,imgsrc,sesize_x,sesize_y))!=0)
    return ret;
  if((ret=flgr2d_erode_rectangle(imgdest,imgtmp,sesize_x,sesize_y))!=0)
    return ret;

  if((ret=flgr2d_arith_sub(imgdest,imgdest,imgsrc))!=0)
    return ret;


  flgr2d_destroy(imgtmp);

  return ret;

}


//! @}
